package web.java.c_Dao;

import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;

import web.java.z_Utils.DBUtils;

/**
 * 最底层的与数据库通信的类，其他的Dao类都必须继承此类，BaseDao定义了两个通用的方法：
 * 1、更新
 * 2、查询
 * */
public class BaseDao {
	//初始化参数
	private Connection conn;
	private PreparedStatement pstmt;
	private ResultSet result;
	
	/**
	 * 1、更新
	 * @param sql 需要更新的sql语句(update, add, delete)
	 * @param params 替换掉sql语句中占位符(?)的参数列表
	 * @return int 返回影响的行数
	 * */
	public int update(String sql, Object[] params){
		//1、获取连接
		conn=DBUtils.getConnection();
		//2、预编译sql语句
		try{
			pstmt=conn.prepareStatement(sql);
			//获取参数元数据，并得到占位的参数个数
			ParameterMetaData pmd=pstmt.getParameterMetaData();
			int paramsCount=pmd.getParameterCount();
			System.out.println("参数的个数为："+paramsCount);
			//给参数赋值
			if(params!=null&&params.length>0){
				for(int i=1;i<=paramsCount;i++){
					//设置参数的位置从1开始，Object数组从0开始
					pstmt.setObject(i,params[i-1]);
				}
			}
			//3、发送参数，执行sql语句
			int rs=pstmt.executeUpdate();
			return rs;
			
		}catch(SQLException e){
			throw new RuntimeException(e);
		}finally{
			DBUtils.closeAll(conn,pstmt);
		}
	}
	/**
	 * 2、查询
	 * @param1 sql
	 * @param2 params
	 * @param3 clazz 对象类型
	 * @return List 返回查询到的结果集对应的对象集合
	 * */
	public <T> List<T> select(String sql,Object[] params, Class<T> clazz){
		//1、建立连接
		conn=DBUtils.getConnection();
		//2、执行sql语句
		try{
			pstmt=conn.prepareStatement(sql);
			//获取参数个数
			int count=pstmt.getParameterMetaData().getParameterCount();
			//若参数个数为0，直接得到结果集，若参数不为零，先设置参数，再执行sql语句
			if(params!=null && count>0){
				//设置参数
				for(int i=0;i<params.length;i++){
					pstmt.setObject(i+1,params[i]);
				}
			}
			//执行sql语句，得到结果集
			result=pstmt.executeQuery();
			//3、获得结果集元数据
			ResultSetMetaData rsMetaData=pstmt.getMetaData();
			//3.1 获取结果集列的个数
			int columnCount=rsMetaData.getColumnCount();
			//4、迭代将结果集数据封装到集合中
			List<T> list=new ArrayList<T>();
			while(result.next()){
				//4.1 得到每一列的值
				T t=clazz.newInstance();
				for(int i=0;i<columnCount;i++){
					//4.1_a 得到每一列的名称，列名从1开始
					//String columnName=rsMetaData.getColumnName(i+1);	//获取的为列的原名称
					String columnName=rsMetaData.getColumnLabel(i+1);	//获取的为列的别名，在多表查询的时候可以避免命名冲突
					//4.1_b 通过列名，得到每一列的值
					Object columnValue=result.getObject(columnName);
					//4.2_b 将每一列的值，封装到对象中
					BeanUtils.copyProperty(t, columnName, columnValue);
				}
				//4.2 封装对象到集合中
				list.add(t);
			}
			//5、返回集合
			return list;
		}catch(Exception e){
			throw new RuntimeException(e);
		}finally{
			DBUtils.closeAll(conn, pstmt, result);
		}
	}
	
}
